let showGuides = false;

// 👆 change to true to see the physics objects

let extraBounce = 0.1;

// 👆 change to 1 for bouncey fun! Change to 2 for everything to bounce out of existence!

let powerMultiplier = 1.2;

// 👆 increase for more POWER!















import {
TextureLoader, RepeatWrapping,
Scene, Color, Fog, HemisphereLight,
PointLight, MeshPhongMaterial, Mesh,
PlaneBufferGeometry, WebGLRenderer,
PerspectiveCamera, Vector3,
Group, BoxGeometry, IcosahedronGeometry,
CylinderGeometry, Cache, PCFSoftShadowMap,
LoadingManager, AxisHelper } from
"https://cdn.skypack.dev/three@0.122.0";

import { GLTFLoader } from "https://cdn.skypack.dev/three@0.122.0/examples/jsm/loaders/GLTFLoader";
import Stats from "https://cdn.skypack.dev/three@0.122.0/examples/jsm/libs/stats.module";
import CANNON from "https://cdn.skypack.dev/cannon@0.6.2";
import gsap from "https://cdn.skypack.dev/gsap@3.5.1";

class Stage
{
  constructor(scale, stageSize, onReady, showStats)
  {
    const manager = new LoadingManager();

    this.showStats = showStats;
    this.models = {};
    this.stats = new Stats();

    manager.onLoad = function () {

      console.log('Loading complete!');
      setTimeout(() => onReady(), 100);

    };

    this.wrappingImages = [
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    ''];

    this.presentTextures = [];

    for (var i in this.wrappingImages)
    {
      var presentTexture = new TextureLoader().load(this.wrappingImages[i]);
      presentTexture.wrapS = RepeatWrapping;
      presentTexture.wrapT = RepeatWrapping;
      presentTexture.repeat.set(3, 3);
      this.presentTextures.push(presentTexture);

    }

    this.container;
    this.scene;
    this.plane;
    this.renderer;
    this.width = 0;
    this.height = 0;
    this.lookAtHelper;
    this.stageSize;

    this.cameraTarget;
    this.camera;

    this.scale = scale;
    this.stageSize = stageSize;

    Cache.enabled = true;

    // SCENE

    this.scene = new Scene();
    this.scene.background = new Color(0x424874);
    this.scene.fog = new Fog(0x424874, 100, 200);
    // this.scene.add(new AxisHelper());

    // LIGHTS

    this.scene.add(new HemisphereLight(0xfefeff, 0xeeeeff, 0.4));

    const ambientLight = new PointLight(0xffffff, 0.1);
    ambientLight.position.set(20, -10, 20);
    this.scene.add(ambientLight);

    const shadowLight = new PointLight(0xffffff, 0.6, 100);
    shadowLight.position.set(10, 0, 4);
    shadowLight.castShadow = true;
    shadowLight.shadow.radius = 16;
    shadowLight.shadow.mapSize.width = 2048;
    shadowLight.shadow.mapSize.height = 2048;
    this.scene.add(shadowLight);

    this.cannonLight = new PointLight(0xEDB458, 0, 100, 2);
    this.cannonLight.position.set(28, -20, 28);
    this.cannonLight.castShadow = true;
    this.cannonLight.shadow.radius = 2;
    this.cannonLight.shadow.mapSize.width = 256;
    this.cannonLight.shadow.mapSize.height = 256;
    this.scene.add(this.cannonLight);

    // FLOOR

    this.plane = new Mesh(
    new PlaneBufferGeometry(1000 * this.scale, 1000 * this.scale),
    new MeshPhongMaterial({ color: 0xDCD6F7 }));

    this.plane.position.set(-10, -30.5, -10);
    this.plane.receiveShadow = true;
    this.plane.rotation.x = -Math.PI / 2;
    this.scene.add(this.plane);

    // RENDERER

    this.renderer = new WebGLRenderer({ antialias: true });
    console.log('pixel ratio:', window.devicePixelRatio);
    // this.renderer.setPixelRatio( window.devicePixelRatio );
    this.renderer.setSize(window.innerWidth, window.innerHeight);
    this.renderer.shadowMap.enabled = true;
    this.renderer.shadowMap.type = PCFSoftShadowMap;

    // CONTAINER

    this.container = document.getElementById('canvas-container');
    this.container.appendChild(this.renderer.domElement);
    if (this.showStats) this.container.appendChild(this.stats.dom);

    // CAMERA

    this.camera = new PerspectiveCamera(40, window.innerWidth / window.innerHeight, 5, 400);
    this.camera.position.set(55, 15, 55);
    this.cameraTarget = new Vector3(0, -22, 0);
    // this.camera.position.set(65, -20, 20);
    // this.cameraTarget = new Vector3( 30, -25, 30 );

    let center = new Vector3((this.stageSize.left + this.stageSize.width / 2) * scale, (this.stageSize.top - this.stageSize.height / 2) * scale, 0);
    const previewCameraDistance = 70 * scale;

    // this.lookAtHelper = this.createBall(0.5, new Color(0xffffff));

    // let stageSizeHelper = new Mesh(
    // new PlaneBufferGeometry( this.stageSize.width * this.scale, this.stageSize.height * this.scale, Math.floor(this.stageSize.width / 5), Math.floor(this.stageSize.height / 5) ),
    // new MeshPhongMaterial ( { color: 0xaaddff, wireframe: false} )
    // );
    // stageSizeHelper.position.set(this.stageSize.left * this.scale, this.stageSize.top * this.scale, 0);
    // stageSizeHelper.applyMatrix4( new THREE.Matrix4().makeTranslation( (this.stageSize.width / 2), -this.stageSize.height / 2, 0 ) );
    // this.scene.add( stageSizeHelper );

    // ROOM

    this.lights = [];

    let colors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff];

    for (let i = 0; i < 3; i++) {

      let group = new Group();
      group.position.x = 1000;

      let color = colors[Math.floor(Math.random() * colors.length)];
      let light = new PointLight(color, 0.5, 50, 1.7);
      // gsap.timeline({ repeat: -1}).to(light, {intensity: 0.7, duration: 0.2}).to(light, {intensity: 0.5, duration: 0.2}).to(light, {intensity: 0.8, duration: 0.2})
      group.add(light);

      let geometry = new IcosahedronGeometry(0.5, 4);
      let material = new MeshPhongMaterial({ color: color, wireframe: false });
      let mesh = new Mesh(geometry, material);
      mesh.castShadow = true;
      group.add(mesh);

      this.scene.add(group);
      this.lights.push(group);
    }


    ///=================
    //    SOFA
    ///=================

    let sofaGroup = new Group();
    sofaGroup.position.y = 1000;
    this.scene.add(sofaGroup);

    var sofaLoader = new GLTFLoader(manager);
    sofaLoader.load("https://assets.codepen.io/557388/sofa.glb", object => {

      object.scene.rotation.y = Math.PI * 0.5;
      let mat = new MeshPhongMaterial({ color: 0xffffff });

      sofaGroup.add(object.scene);

      object.scene.traverse(function (child) {

        if (child.isMesh) {
          child.position.set(0, 0, 0);
          child.castShadow = true;
          child.receiveShadow = true;
          child.material = mat;
        } else
        if (child.isLight)
        {
          child.visible = false; //child.intensity = 0;
        }

      });

      this.models.sofa = sofaGroup;
    });

    ///=================
    //    TREE
    ///=================

    let treeGroup = new Group();
    treeGroup.position.y = 1000;
    this.scene.add(treeGroup);

    var treeLoader = new GLTFLoader(manager);
    treeLoader.load("https://assets.codepen.io/557388/PineTree.gltf", object => {

      object.scene.position.set(0, 0, -17);
      object.scene.scale.set(1.2, 1.2, 1.2);
      object.scene.rotation.x = Math.PI * 0.5;

      treeGroup.add(object.scene);
      treeGroup.position.y = 1000;

      object.scene.traverse(function (child) {

        let mat = new MeshPhongMaterial({ color: 0x99dd66 });
        if (child.isMesh) {
          child.castShadow = true;
          child.receiveShadow = true;
          child.material = mat;
        } else
        if (child.isLight)
        {
          child.visible = false; //child.intensity = 0;
        }

      });

      this.models.tree = treeGroup;
    });

    ///=================
    //    FIREPLACE
    ///=================

    let fireplaceGroup = new Group();
    this.scene.add(fireplaceGroup);

    var fireplaceLoader = new GLTFLoader(manager);
    fireplaceLoader.load("https://assets.codepen.io/557388/fireplace.gltf", object => {

      object.scene.position.set(0, -29, -19.5);
      object.scene.scale.set(4, 4, 4);
      object.scene.rotation.y = -Math.PI * 0.5;
      fireplaceGroup.add(object.scene);



      object.scene.traverse(function (child) {

        let mat = new MeshPhongMaterial({ color: 0xffffff });
        if (child.isMesh) {
          child.castShadow = true;
          child.receiveShadow = true;
          child.material = mat;
        } else
        if (child.isLight)
        {
          child.visible = false; //child.intensity = 0;
        }

      });

      this.models.fireplace = fireplaceGroup;
    });

    ///=================
    //    TABLE
    ///=================

    let tableGroup = new Group();
    tableGroup.position.y = 1000;
    this.scene.add(tableGroup);

    var tableLoader = new GLTFLoader(manager);
    tableLoader.load("https://assets.codepen.io/557388/table.gltf", object => {

      object.scene.position.set(0, -6.3, 0);
      object.scene.scale.set(2, 2, 2);
      tableGroup.add(object.scene);

      object.scene.traverse(function (child) {

        let mat = new MeshPhongMaterial({ color: 0xffffff });
        if (child.isMesh) {
          child.castShadow = true;
          child.receiveShadow = true;
          child.material = mat;
        } else
        if (child.isLight)
        {
          child.visible = false;
          // child.intensity = 0;
        }

      });

      this.models.table = tableGroup;
    });

    ///=================
    //    TV STAND
    ///=================

    let standGroup = new Group();
    standGroup.position.y = 1000;
    this.scene.add(standGroup);

    var tableLoader = new GLTFLoader(manager);
    tableLoader.load("https://assets.codepen.io/557388/stand.gltf", object => {

      object.scene.rotation.y = Math.PI * 0.5;
      standGroup.add(object.scene);

      object.scene.traverse(function (child) {

        let mat = new MeshPhongMaterial({ color: 0xffffff });
        if (child.isMesh) {
          child.castShadow = true;
          child.receiveShadow = true;
          child.material = mat;
        } else
        if (child.isLight)
        {
          child.visible = false; //child.intensity = 0;
        }

      });

      this.models.stand = standGroup;
    });

    ///=================
    //    TV
    ///=================

    let tvGroup = new Group();
    tvGroup.position.y = 1000;
    this.scene.add(tvGroup);

    var tableLoader = new GLTFLoader(manager);
    tableLoader.load("https://assets.codepen.io/557388/tv.gltf", object => {

      object.scene.scale.set(2, 2, 2);
      object.scene.rotation.y = Math.PI * 0.5;
      tvGroup.add(object.scene);

      object.scene.traverse(function (child) {

        let mat = new MeshPhongMaterial({ color: 0xffffff });
        if (child.isMesh) {
          child.castShadow = true;
          child.receiveShadow = true;
          child.material = mat;
        } else
        if (child.isLight)
        {
          child.visible = false; //child.intensity = 0;
        }

      });

      this.models.tv = tvGroup;
    });

    ///=================
    //    POT
    ///=================

    let potGroup = new Group();
    potGroup.position.y = 1000;
    this.scene.add(potGroup);

    var tableLoader = new GLTFLoader(manager);
    tableLoader.load("https://assets.codepen.io/557388/pot.gltf", object => {

      object.scene.position.set(0, 0, -15);
      object.scene.scale.set(6, 6, 6);
      object.scene.rotation.x = Math.PI * 0.5;
      potGroup.add(object.scene);

      object.scene.traverse(function (child) {

        let mat = new MeshPhongMaterial({ color: 0xB2967D });
        if (child.isMesh) {
          child.castShadow = true;
          child.receiveShadow = true;
          child.material = mat;
        } else
        if (child.isLight)
        {
          child.visible = false; //child.intensity = 0;
        }

      });

      this.models.pot = potGroup;
    });

    ///=================
    //    CANNON
    ///=================

    let cannonGroup = new Group();
    this.scene.add(cannonGroup);

    var tableLoader = new GLTFLoader(manager);
    tableLoader.load("https://assets.codepen.io/557388/cannon2.gltf", object => {

      object.scene.position.set(30, -30, 30);
      object.scene.scale.set(3, 3, 3);
      object.scene.rotation.y = Math.PI * 1.25;
      cannonGroup.add(object.scene);

      object.scene.traverse(function (child) {

        if (child.isMesh) {
          child.castShadow = true;
        }
        if (child.isLight)
        {
          child.visible = false; //child.intensity = 0;
        }

      });

      this.models.cannon = cannonGroup;
    });


    ///=================
    //    SNOWMAN
    ///=================

    let snowmanGroup = new Group();
    snowmanGroup.position.y = 1000;
    this.scene.add(snowmanGroup);

    var snowmanLoader = new GLTFLoader(manager);
    snowmanLoader.load("https://assets.codepen.io/557388/snowman.gltf", object => {

      //object.scene.position.set(30, -30, 30);
      object.scene.scale.set(2.5, 2.5, 2.5);
      // object.scene.rotation.y = Math.PI * 1.25;
      snowmanGroup.add(object.scene);

      object.scene.traverse(function (child) {

        if (child.isMesh) {
          child.castShadow = true;
        }
        if (child.isLight)
        {
          child.visible = false; //child.intensity = 0;
        }

      });

      this.models.snowman = snowmanGroup;
    });

    ///=================
    //    STAR
    ///=================

    let starGroup = new Group();
    starGroup.position.y = 1000;
    this.scene.add(starGroup);

    var starLoader = new GLTFLoader(manager);
    starLoader.load("https://assets.codepen.io/557388/star.gltf", object => {

      object.scene.position.set(-1, 0, 0);
      object.scene.scale.set(0.01, 0.01, 0.01);
      object.scene.rotation.y = Math.PI * .5;
      starGroup.add(object.scene);

      object.scene.traverse(function (child) {

        if (child.isMesh) {
          child.castShadow = true;
        }
        if (child.isLight)
        {
          child.visible = false;
          // child.intensity = 0;

        }

      });

      this.models.star = starGroup;
    });



    this.onResize();
  }

  setPlane(physicsPlane)
  {
    this.plane.position.copy(physicsPlane.position);
    this.plane.quaternion.copy(physicsPlane.quaternion);
  }

  render()
  {
    this.camera.lookAt(this.cameraTarget);
    this.renderer.render(this.scene, this.camera);

    if (this.showStats) this.stats.update();
  }

  onResize()
  {
    this.camera.aspect = window.innerWidth / window.innerHeight;

    this.camera.updateProjectionMatrix();
    this.renderer.setSize(window.innerWidth, window.innerHeight);

    var aspect = window.innerWidth / window.innerHeight;
    this.width = window.innerWidth;
    this.height = window.innerHeight;

  }

  createBox(width, height, depth, color = 0xffffff, present = false)
  {
    let geometry = new BoxGeometry(width * this.scale, height * this.scale, depth * this.scale);
    let texture = present ? this.presentTextures[Math.floor(Math.random() * this.presentTextures.length)] : null;
    let material = new MeshPhongMaterial({ color: color, shininess: present ? 100 : 30, map: texture });
    let mesh = new Mesh(geometry, material);
    mesh.castShadow = true;
    mesh.receiveShadow = true;
    this.scene.add(mesh);
    return mesh;
  }

  createSphere(radius, color)
  {
    let geometry = new IcosahedronGeometry(radius, 3);
    let material = new MeshPhongMaterial({ color: color, shininess: 30 });
    let mesh = new Mesh(geometry, material);
    mesh.castShadow = true;
    mesh.receiveShadow = true;
    this.scene.add(mesh);
    return mesh;
  }

  createBall(size, color, light = false)
  {

    if (light && this.lights.length)
    {
      return this.lights.shift();
    }

    let group = new Group();
    let material = new MeshPhongMaterial({ color: color, wireframe: false });
    let ball = new IcosahedronGeometry(size, 4);
    let mesh = new Mesh(ball, material);
    mesh.castShadow = true;
    group.add(mesh);

    if (!light)
    {
      let cap = new CylinderGeometry(size / 2, size / 2, size, 5);
      let capMat = new MeshPhongMaterial({ color: 0xFFD338, wireframe: false });
      let capMesh = new Mesh(cap, capMat);
      capMesh.castShadow = true;
      capMesh.position.y = size * 0.75;
      group.add(capMesh);

    }

    this.scene.add(group);
    return group;
  }

  createCylinder(radiusTop, radiusBottom, height, numSegments)
  {
    const group = new Group();
    const geometry = new CylinderGeometry(radiusTop, radiusBottom, height, numSegments);
    const material = new MeshPhongMaterial({ color: 0xff0000 });
    const cylinder = new Mesh(geometry, material);
    // cylinder.position.set(x, y, z
    cylinder.rotation.x = Math.PI * 0.5;
    group.add(cylinder);
    this.scene.add(group);
    return group;
  }}




const PHYSICS_MATERIAL = {
  lowBounce: 'lowbounce',
  normalBounce: 'normalbounce',
  highBounce: 'highbounce' };


class Physics
{
  constructor(scale = 1, stageSize)
  {
    this.scale = 1;
    this.stageSize;

    this.scale = scale;
    this.stageSize = stageSize;

    this.materials = {};

    let mainMaterial = new CANNON.Material('main');
    mainMaterial.friction = 1;

    this.materials[PHYSICS_MATERIAL.lowBounce] = new CANNON.ContactMaterial(mainMaterial, mainMaterial, { friction: 2, restitution: 0 + extraBounce });
    this.materials[PHYSICS_MATERIAL.normalBounce] = new CANNON.ContactMaterial(mainMaterial, mainMaterial, { friction: 2, restitution: 0 + extraBounce });
    this.materials[PHYSICS_MATERIAL.highBounce] = new CANNON.ContactMaterial(mainMaterial, mainMaterial, { friction: 2, restitution: 1.5 + extraBounce });

    // WORLD

    this.world = new CANNON.World();
    this.world.gravity.set(0, -60 * this.scale, 0);
    this.world.broadphase = new CANNON.NaiveBroadphase();
    this.world.solver.iterations = 4;

    this.world.addContactMaterial(this.materials[PHYSICS_MATERIAL.lowBounce]);
    this.world.addContactMaterial(this.materials[PHYSICS_MATERIAL.normalBounce]);
    this.world.addContactMaterial(this.materials[PHYSICS_MATERIAL.highBounce]);

    // GROUND

    this.groundBody = new CANNON.Body({ mass: 0, material: mainMaterial });
    let groundShape = new CANNON.Plane();
    this.groundBody.addShape(groundShape);
    var rotate = new CANNON.Vec3(1, 0, 0);
    this.groundBody.quaternion.setFromAxisAngle(rotate, -(Math.PI / 2));
    this.groundBody.position.set(0, (this.stageSize.top - this.stageSize.height) * scale, 0);
    this.world.addBody(this.groundBody);

  }

  createBody(mass, position, rotation, material = PHYSICS_MATERIAL.normalBounce)
  {
    let body = new CANNON.Body({
      type: mass == 0 ? CANNON.Body.KINEMATIC : CANNON.Body.DYNAMIC,
      material: this.materials[material],
      mass: mass * this.scale,
      position: new CANNON.Vec3(position.x * this.scale, position.y * this.scale, position.z * this.scale) // m
    });

    Object.keys(rotation || {}).forEach((key) =>
    {
      this.setAngle(body, rotation[key], key);
    });
    this.world.addBody(body);

    return body;
  }

  createBoxShape(width, height, depth)
  {
    return new CANNON.Box(new CANNON.Vec3(width / 2 * this.scale, height / 2 * this.scale, depth / 2 * this.scale));
  }

  createCylinderShape(radiusTop, radiusBottom, height, segments)
  {
    return new CANNON.Cylinder(radiusTop, radiusBottom, height, segments);
  }

  createSphereShape(radius)
  {
    return new CANNON.Sphere(radius);
  }

  // createCylinder(x, y, z, radiusTop, radiusBottom,  height, numSegments)
  // {
  // 	let shape = new CANNON.Cylinder(radiusTop, radiusBottom,  height, numSegments);

  // 	let body = new CANNON.Body({
  // 		material: this.materials[PHYSICS_MATERIAL.normalBounce],
  // 		mass: 15 * this.scale,
  // 		position: new CANNON.Vec3(x * this.scale, y * this.scale, z * this.scale), // m
  // 	});
  // 	body.addShape(shape);
  // 	this.setAngle(body, -Math.PI * 0.5, 'x');

  // 	this.world.addBody(body);

  // 	return body;
  // }

  createBox(width, height, depth, x, y, z, mass = 0, rotation = 0, trigger)
  {
    let shape = new CANNON.Box(new CANNON.Vec3(width / 2 * this.scale, height / 2 * this.scale, depth / 2 * this.scale));
    let body = new CANNON.Body({
      type: mass == 0 ? CANNON.Body.KINEMATIC : CANNON.Body.DYNAMIC,
      material: this.materials[PHYSICS_MATERIAL.normalBounce],
      mass: mass * this.scale,
      position: new CANNON.Vec3(x * this.scale, y * this.scale, z * this.scale) // m
    });
    body.addShape(shape);
    body.collisionResponse = trigger ? false : true;

    if (trigger)
    {
      body.addEventListener('collide', () => trigger());
    }

    this.setAngle(body, rotation);

    this.world.addBody(body);

    return body;
  }

  setAngle(body, rotation, direction = 'z')
  {
    let q = new CANNON.Quaternion();
    let x = direction === 'x' ? 1 : 0;
    let y = direction === 'y' ? 1 : 0;
    let z = direction === 'z' ? 1 : 0;
    q.setFromAxisAngle(new CANNON.Vec3(x, y, z), rotation);
    body.quaternion = q.mult(body.quaternion);
  }

  createBall(size, x = 0, y = 0, z = 0)
  {
    let shape = new CANNON.Sphere(size);
    let body = new CANNON.Body({
      material: this.materials[PHYSICS_MATERIAL.highBounce],
      mass: 1 * this.scale,
      position: new CANNON.Vec3(x * this.scale, y * this.scale, z * this.scale) // m
    });
    body.addShape(shape);

    this.world.addBody(body);

    return body;
  }

  createCylinder(x, y, z, radiusTop, radiusBottom, height, numSegments)
  {
    let shape = new CANNON.Cylinder(radiusTop, radiusBottom, height, numSegments);

    let body = new CANNON.Body({
      material: this.materials[PHYSICS_MATERIAL.normalBounce],
      mass: 15 * this.scale,
      position: new CANNON.Vec3(x * this.scale, y * this.scale, z * this.scale) // m
    });
    body.addShape(shape);
    this.setAngle(body, -Math.PI * 0.5, 'x');

    this.world.addBody(body);

    return body;
  }

  remove(body)
  {
    this.world.remove(body);
  }

  tick()
  {
    this.world.step(1 / 60);
  }}



console.clear();

const DIRECTION = {
  left: 'LEFT',
  right: 'RIGHT' };


const GAME_STATE = {
  loading: 'loading',
  intro: 'intro',
  waiting: 'waiting',
  game: 'game' };


let sounds = {
  fire: [new Audio('https://assets.codepen.io/557388/fire_01.mp3'), new Audio('https://assets.codepen.io/557388/fire_02.mp3')],
  bells: [new Audio('https://assets.codepen.io/557388/bells_01.mp3')],
  bing: [new Audio('https://assets.codepen.io/557388/bing_01.mp3'), new Audio('https://assets.codepen.io/557388/bing_02.mp3')] };


let gameState = GAME_STATE.loading;

let physicsItems = [];
let stage;
let physics;

let mousePos = { x: 0, y: 0 };



let count = 0;
let cannonFlash;
let cannonRecoil;
let stars = [];

const introSteps = [init, prepUI, loadComplete, dropIn, createClickListeners, introRoom, introCannon, introStart, startGame];

function next()
{
  if (introSteps.length)
  {
    introSteps.shift()();
  }
}

function loadComplete()
{
  const loadingScreen = document.querySelector('#loading');
  loadingScreen.innerHTML = '';
  setState(GAME_STATE.intro);

  gsap.to(loadingScreen, { autoAlpha: 0, duration: 1.5 });
  setTimeout(() => next(), 1000);
}

function prepUI()
{
  gsap.set('#steve', { y: '50%', scale: 0, rotation: 45 });
  gsap.set('#bubble', { transformOrigin: '100% 50%', autoAlpha: 0, x: '+=50', rotation: 5, scale: 0.9 });

  next();
}

function dropIn()
{
  createSofa();
  createTable();
  createStand();
  createTV();

  next();
}

function setState(newState)
{
  gameState = newState;
  document.body.setAttribute('class', gameState);
}

function onMouseMove(event)
{
  mousePos = { x: event.clientX, y: event.clientY };
}

function createClickListeners()
{
  document.addEventListener('keypress', onClick, false);
  document.addEventListener('click', onClick, false);
  document.addEventListener('mousemove', onMouseMove, false);

  next();
}

function introRoom()
{
  setState(GAME_STATE.intro);
  let roomTL = gsap.timeline({ onComplete: () => setState(GAME_STATE.waiting) });
  roomTL.to('#steve', { delay: 1, y: 0, rotation: 0, scale: 1, ease: 'power4.out', duration: 0.6, onComplete: () => playSound('bing') });
  roomTL.fromTo('#bubble', { autoAlpha: 0, y: 0, x: '+=50', rotation: 5, scale: 0.9 }, { autoAlpha: 1, rotation: 0, scale: 1, x: 0, ease: 'elastic', duration: 1 });

}

function introCannon()
{
  setState(GAME_STATE.intro);
  const steveEl = document.querySelector('#steve');
  const textEl = document.querySelector('#text');
  const textHighlightEl = document.querySelector('#text-highlight');

  let cannonTL = gsap.timeline({ onComplete: () => setState(GAME_STATE.waiting), defaults: { ease: 'power4.easeInOut', duration: .8 } });
  cannonTL.to(stage.camera.position, { x: 65, y: -20, z: 20 });
  cannonTL.to(stage.cameraTarget, { x: 30, y: -25, z: 30 }, 0);
  cannonTL.to('#bubble', { autoAlpha: 0, y: '-=30', scale: 0.5, duration: 0.3, ease: 'power2.in' }, 0);
  cannonTL.to(steveEl, { y: '-=20', duration: 0.1, onComplete: () => {
      steveEl.setAttribute('src', 'https://assets.codepen.io/557388/happy.svg');
      textEl.textContent = "But wait, we have this ";
      textHighlightEl.textContent = "Christmas Cannon!!";
      setTimeout(() => playSound('bing'), 300);

    } }, 0.5);
  cannonTL.fromTo('#bubble', { autoAlpha: 0, y: 0, x: '+=50', rotation: 5, scale: 0.9 }, { autoAlpha: 1, rotation: 0, scale: 1, x: 0, ease: 'elastic', duration: 1 });
  cannonTL.to(steveEl, { y: 0, duration: .7, ease: 'bounce' }, 0.6);
}

function introStart()
{
  setState(GAME_STATE.intro);
  const steveEl = document.querySelector('#steve');
  const textEl = document.querySelector('#text');
  const textHighlightEl = document.querySelector('#text-highlight');

  let cannonTL = gsap.timeline({ onComplete: () => setState(GAME_STATE.game), defaults: { ease: 'power4.easeInOut', duration: .8 } });
  cannonTL.to(stage.camera.position, { x: 55, y: 15, z: 55 });
  cannonTL.to(stage.cameraTarget, { x: 0, y: -22, z: 0, duration: 1.4 }, 0);
  cannonTL.to('#bubble', { autoAlpha: 0, y: '-=30', scale: 0.5, duration: 0.3, ease: 'power2.in' }, 0);
  cannonTL.to(steveEl, { y: '-=20', duration: 0.1, onComplete: () => {
      steveEl.setAttribute('src', 'https://assets.codepen.io/557388/steve.svg');
      textEl.textContent = "Click or tap to fire the Christmas Cannon, let’s make this room more festive!!";
      textHighlightEl.textContent = "";
      setTimeout(() => playSound('bing'), 700);
    } }, 0.5);
  cannonTL.fromTo('#bubble', { autoAlpha: 0, y: 0, x: '+=50', rotation: 5, scale: 0.9 }, { autoAlpha: 1, rotation: 0, scale: 1, x: 0, ease: 'elastic', duration: 1 });
  cannonTL.to(steveEl, { y: 0, duration: .7, ease: 'bounce' }, 0.6);
}

function endMessage()
{
  const steveEl = document.querySelector('#steve');
  const textEl = document.querySelector('#text');
  const textHighlightEl = document.querySelector('#text-highlight');

  let changed = false;
  steveEl.addEventListener('click', event => {
    event.stopPropagation();
    if (!changed)
    {
      changed = true;
      let steveTL = gsap.timeline();
      steveTL.to(steveEl, { y: '-=40', duration: 0.1, onComplete: () => {
          steveEl.setAttribute('src', 'https://assets.codepen.io/557388/snowman.svg');
        } }, 0);
      steveTL.to(steveEl, { y: 0, duration: .7, ease: 'bounce' }, 0.1);
    } else
    window.open('https://ste.vg/pJ96mS5DC', '_blank');
  });

  textEl.addEventListener('click', event => {
    event.stopPropagation();
    startGame();
    // window.open('https://www.twitter.com/steeevg/','_blank');
  });

  // steveEl.setAttribute('src', 'https://assets.codepen.io/557388/snowman.svg');
  textEl.innerHTML = `Yay! So much better.`;


  // Be sure to send a screenshot to <a href="https://twitter.com/steeevg/" target="_blank">@steeevg</a>, he’d love to see it!`;
  textHighlightEl.textContent = "Merry Christmas!";

  let roomTL = gsap.timeline();
  setTimeout(() => playSound('bing'), 700);
  roomTL.to('#steve', { y: 0, rotation: 0, scale: 1, ease: 'power4.out', duration: 0.6 });
  roomTL.fromTo('#bubble', { autoAlpha: 0, y: 0, x: '+=50', rotation: 5, scale: 0.9 }, { autoAlpha: 1, rotation: 0, scale: 1, x: 0, ease: 'elastic', duration: 1 });
}

function hideEndMessage()
{

}

function playSound(name)
{
  let options = sounds[name];
  if (options)
  {
    let sound = options[Math.floor(Math.random() * options.length)];
    sound.currentTime = 0;
    sound.play();
  }
}

function startGame()
{
  setState(GAME_STATE.game);

  let gameStartTL = gsap.timeline({ defaults: { ease: 'power4.easeInOut', duration: .5 } });
  gameStartTL.to('#bubble', { autoAlpha: 0, y: '-=30', scale: 0.5, duration: 0.3, ease: 'power2.in' }, 0);
  gameStartTL.to('#steve', { y: '100%', scale: 0, rotation: 45 }, 0);
}

function onClick(event)
{
  if (event) event.preventDefault();

  let coords = {
    x: event.clientX || mousePos.x,
    y: event.clientY || mousePos.y };



  switch (gameState) {

    case GAME_STATE.waiting:
      next();
      break;
    case GAME_STATE.game:
      fire(coords);
      break;
    default:
      return;}


}

function fire(coords)
{
  if (count === 0) next();
  count++;
  let item;

  let randomItems = [addBall, createStar];

  if (count === 50) item = createSnowman();else
  if (count === 10) item = createTree();else
  if (stars.length && Math.random() > 0.8) item = createStar(); //randomItems[Math.floor(Math.random() * randomItems.length)]();
  else item = addBall();

  if (count === 100)
  {
    setTimeout(() => endMessage(), 1000);
  }

  playSound('fire');
  // if(Math.random() > 0.8) playSound('bells');

  let range = stage.height * 0.4;
  let x = -60;
  // let y = 20;
  let z = -60;

  let xStart = stage.width / 2 - range;
  let xEnd = stage.width / 2 + range;
  if (coords.x > stage.width / 2)
  {
    if (coords.x > xEnd) x = -20;else

    {
      let r = coords.x - stage.width / 2;
      x = -20 + (range - r) / range * -40;
    }
  }

  // let yStart = (stage.width / 2);
  if (coords.x < stage.width / 2)
  {
    if (coords.x < xStart) z = -20;else

    {
      let r = coords.x - xStart;
      z = -20 + r / range * -40;
    }
  }

  let hRange = 100;
  let y = 60 - coords.y / stage.height * hRange;

  item.physics.velocity.set(x * powerMultiplier, y, z * powerMultiplier);
  const angularRandomness = 10;
  item.physics.angularVelocity.set(
  Math.random() * angularRandomness - angularRandomness / 2,
  Math.random() * angularRandomness - angularRandomness / 2,
  Math.random() * angularRandomness - angularRandomness / 2);
  item.physics.angularDamping = 0.8;

  cannonFlash.restart();
  cannonRecoil.restart();
}

function onReady()
{
  // createTree();

  setState(GAME_STATE.intro);

  cannonFlash = gsap.timeline();
  cannonFlash.fromTo(stage.cannonLight, { intensity: 2 }, { intensity: 0, duration: .3 });

  cannonRecoil = gsap.timeline();
  cannonRecoil.to(stage.models.cannon.position, { x: '+=3', z: '+=3', duration: 0.1, ease: 'Power2.out' }).to(stage.models.cannon.position, { x: '-=3', z: '-=3', duration: 0.4 });
  // cannonFlash.stop();

  for (let i = 0; i < 20; i++) {
    let star = stage.models.star.clone();
    stars.push(star);
    stage.scene.add(star);

  }

  setTimeout(() => {
    animate();
    next();
  }, 100);

}




function addBall()
{
  // gsap.to(stage.cameraTarget, {x: stageSize.left + (stageSize.width * 0.5), ease: 'Power4.inOut', duration: 1})



  let x = 35;
  let y = -15;
  let z = 35;

  let width = 1 + Math.random() * 4;
  let height = 1 + Math.random() * 4;
  let depth = 1 + Math.random() * 4;

  let isBall = Math.random() > 0.5;

  let light = Math.random() > 0.8;
  var size = light ? .5 : .8;

  var physicsItem = {
    mesh: isBall ? stage.createBall(size, showGuides ? 0xFF0000 : Math.random() * 0xFFFFFF, light) : stage.createBox(width, height, depth, showGuides ? 0xFF0000 : 0xFFFFFF, !showGuides),
    physics: isBall ? physics.createBall(size, x, y, z) : physics.createBox(width, height, depth, x, y, z, 2),
    previousPosition: new CANNON.Vec3(x, y, z),
    rotation: 0,
    rotationVelocity: 0 };


  // physicsItem.physics.velocity.set(-20 - (Math.random() * 50), 1 + (Math.random() * 10), -20 - (Math.random() * 50))


  // -60 => -20

  // 10 => 30

  // -20 => -60

  // physicsItem.physics.velocity.set(-60, 10, -60)
  // const angularRandomness = 10;
  // physicsItem.physics.angularVelocity.set(
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)),
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)),
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)))
  // physicsItem.physics.angularDamping = 0.8;

  physicsItems.push(physicsItem);

  return physicsItem;

  // if(pauseTimer) clearTimeout(pauseTimer);
  // pauseTimer = setTimeout( _ => doPhysics = false, 7000);
}

function createStaticBox(settings)
{
  // const z = 1;
  var physicsItem = {
    mesh: settings.show ? stage.createBox(settings.width, settings.height, settings.depth, settings.color) : null,
    physics: physics.createBox(settings.width, settings.height, settings.depth, settings.x, settings.y, settings.z, 0, settings.rotation, settings.trigger),
    previousPosition: new CANNON.Vec3(settings.x, settings.y, settings.z),
    rotation: settings.rotation,
    rotationVelocity: 0 };

  physicsItems.push(physicsItem);

  return physicsItem;
}

function animate()
{
  physics.tick();

  for (var i in physicsItems)
  {
    if (physicsItems[i].mesh)
    {
      physicsItems[i].mesh.position.copy(physicsItems[i].physics.position);
      physicsItems[i].mesh.quaternion.copy(physicsItems[i].physics.quaternion);
    }

  }

  stage.render();

  requestAnimationFrame(animate);
}

function init()
{
  console.log('init()');



  let worldScale = 1;

  let stageSize = {
    left: -20,
    width: 40,
    top: 0,
    height: 30 };


  stage = new Stage(worldScale, stageSize, onReady, showGuides);
  physics = new Physics(worldScale, stageSize);

  window.addEventListener('resize', () => {stage.onResize();}, false);




  let staticItems = [
  {
    show: true,
    x: stageSize.left,
    y: -18.5,
    z: 0,
    width: 25,
    height: 2,
    depth: 40,
    color: 0xcccccc,
    rotation: Math.PI * 0.5 },

  {
    show: true,
    x: stageSize.left + stageSize.width / 2 - 0.5,
    y: -18.5,
    z: -20,
    width: 41,
    height: 25,
    depth: 2,
    color: 0xcccccc,
    rotation: 0 },

  {
    show: true,
    x: stageSize.left + stageSize.width / 2,
    y: -30,
    z: 0,
    width: 40,
    height: 2,
    depth: 40,
    color: 0xcccccc,
    rotation: 0 },

  {
    show: showGuides,
    x: 5.5,
    y: -25,
    z: -18,
    width: 3,
    height: 14,
    depth: 3,
    color: 0xff0000,
    rotation: 0 },

  {
    show: showGuides,
    x: -5,
    y: -25,
    z: -18,
    width: 3,
    height: 14,
    depth: 3,
    color: 0xff0000,
    rotation: 0 },

  {
    show: showGuides,
    x: 0,
    y: -19,
    z: -18,
    width: 10,
    height: 2.5,
    depth: 3,
    color: 0xff0000,
    rotation: 0 },

  {
    show: showGuides,
    x: 0,
    y: -17.7,
    z: -18,
    width: 15.2,
    height: 0.5,
    depth: 3.3,
    color: 0xff0000,
    rotation: 0 }];




  staticItems.forEach(settings => {
    createStaticBox(settings);
  });






  // addBall();
}

function createSofa()
{
  let body = physics.createBody(5, { x: 12, y: -10, z: 2 }, { y: Math.PI * 1.023, x: Math.PI * 0.01 }, PHYSICS_MATERIAL.lowBounce);

  let shapes = [{
    show: false,
    x: 0,
    y: -1.5,
    z: 0,
    width: 9,
    height: 2.6,
    depth: 23.5,
    rotation: 0 },

  {
    show: false,
    x: -4,
    y: 0,
    z: 0,
    width: 2.3,
    height: 6,
    depth: 23,
    rotation: 0 },

  {
    show: false,
    x: 0,
    y: 0,
    z: -10.3,
    width: 9,
    height: 2,
    depth: 2.5,
    rotation: 0 },

  {
    show: false,
    x: 0,
    y: 0,
    z: 10.3,
    width: 9,
    height: 2,
    depth: 2.5,
    rotation: 0 },

  {
    show: false,
    x: -2.2,
    y: 2.8,
    z: 0,
    width: 3.5,
    height: 1,
    depth: 18.5,
    rotation: -Math.PI * 0.4 }];


  stage.models.sofa.position.y = 0;

  let sofaGroup = new Group();
  sofaGroup.add(stage.models.sofa);
  stage.scene.add(sofaGroup);

  shapes.forEach(box => {
    let shape = physics.createBoxShape(box.width, box.height, box.depth);

    if (showGuides)
    {
      let b = stage.createBox(box.width, box.height, box.depth, 0xff0000);
      b.position.set(box.x, box.y, box.z);
      b.rotation.set(0, 0, box.rotation);
      sofaGroup.add(b);
    }

    body.addShape(shape, new CANNON.Vec3(box.x, box.y, box.z), new CANNON.Quaternion(0, 0, box.rotation));
  });

  var physicsItem = {
    mesh: sofaGroup,
    physics: body };


  physicsItem.physics.velocity.set(0, -20, 0);
  // const angularRandomness = 10;
  // physicsItem.physics.angularVelocity.set(
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)),
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)),
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)))
  // physicsItem.physics.angularDamping = 0.8;

  physicsItems.push(physicsItem);
}

function createTable()
{
  let body = physics.createBody(3, { x: 0, y: -13, z: 2 }, { y: -Math.PI * 1.013, x: Math.PI * 0.01 }, PHYSICS_MATERIAL.lowBounce);

  let shapes = [
  {
    x: 0.5,
    y: -1.2,
    z: 0,
    width: 7,
    height: 0.5,
    depth: 16,
    rotation: 0 },

  {
    x: 4,
    y: -2.5,
    z: 7.8,
    width: 0.5,
    height: 2.5,
    depth: 0.5,
    rotation: 0 },

  {
    x: 4,
    y: -2.5,
    z: -7.8,
    width: 0.5,
    height: 2.5,
    depth: 0.5,
    rotation: 0 },

  {
    x: -2.8,
    y: -2.5,
    z: 7.8,
    width: 0.5,
    height: 2.5,
    depth: 0.5,
    rotation: 0 },

  {
    x: -2.8,
    y: -2.5,
    z: -7.8,
    width: 0.5,
    height: 2.5,
    depth: 0.5,
    rotation: 0 }];



  stage.models.table.position.y = 0;

  let tableGroup = new Group();
  tableGroup.add(stage.models.table);
  stage.scene.add(tableGroup);

  shapes.forEach(box => {
    let shape = physics.createBoxShape(box.width, box.height, box.depth);

    if (showGuides)
    {
      let b = stage.createBox(box.width, box.height, box.depth, 0xff0000);
      b.position.set(box.x, box.y, box.z);
      b.rotation.set(0, 0, box.rotation);
      tableGroup.add(b);
    }

    body.addShape(shape, new CANNON.Vec3(box.x, box.y, box.z), new CANNON.Quaternion(0, 0, box.rotation));
  });

  var physicsItem = {
    mesh: tableGroup,
    physics: body };


  physicsItem.physics.velocity.set(0, -20, 0);
  // const angularRandomness = 10;
  // physicsItem.physics.angularVelocity.set(
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)),
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)),
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)))
  // physicsItem.physics.angularDamping = 0.8;

  physicsItems.push(physicsItem);
}

function createStand()
{
  let body = physics.createBody(6, { x: -16, y: -10, z: 0 }, { y: -Math.PI * 0.001, x: Math.PI * 0.05 }, PHYSICS_MATERIAL.lowBounce);

  let shapes = [
  {
    x: 0,
    y: 1.5,
    z: 0,
    width: 4.5,
    height: 4.8,
    depth: 18,
    rotation: 0 }];




  stage.models.stand.position.y = 0;

  let standGroup = new Group();
  standGroup.add(stage.models.stand);
  stage.scene.add(standGroup);

  shapes.forEach(box => {
    let shape = physics.createBoxShape(box.width, box.height, box.depth);

    if (showGuides)
    {
      let b = stage.createBox(box.width, box.height, box.depth, 0xff0000);
      b.position.set(box.x, box.y, box.z);
      b.rotation.set(0, 0, box.rotation);
      standGroup.add(b);
    }

    body.addShape(shape, new CANNON.Vec3(box.x, box.y, box.z), new CANNON.Quaternion(0, 0, box.rotation));
  });

  var physicsItem = {
    mesh: standGroup,
    physics: body };


  physicsItem.physics.velocity.set(0, -20, 0);
  // const angularRandomness = 10;
  // physicsItem.physics.angularVelocity.set(
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)),
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)),
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)))
  // physicsItem.physics.angularDamping = 0.8;

  physicsItems.push(physicsItem);
}

function createTV()
{
  let body = physics.createBody(2, { x: -15.5, y: 0, z: 0 }, { y: -Math.PI * 0.001, x: Math.PI * 0.001 }, PHYSICS_MATERIAL.lowBounce);

  let shapes = [
  {
    x: 0,
    y: 4.5,
    z: 0.5,
    width: 1.5,
    height: 9.5,
    depth: 18,
    rotation: 0 },

  {
    x: 0,
    y: -1.6,
    z: 0.5,
    width: 2.5,
    height: 0.5,
    depth: 6.8,
    rotation: 0 }];




  stage.models.tv.position.y = 0;

  let tvGroup = new Group();
  tvGroup.add(stage.models.tv);
  stage.scene.add(tvGroup);

  shapes.forEach(box => {
    let shape = physics.createBoxShape(box.width, box.height, box.depth);

    if (showGuides)
    {
      let b = stage.createBox(box.width, box.height, box.depth, 0xff0000);
      b.position.set(box.x, box.y, box.z);
      b.rotation.set(0, 0, box.rotation);
      tvGroup.add(b);
    }

    body.addShape(shape, new CANNON.Vec3(box.x, box.y, box.z), new CANNON.Quaternion(0, 0, box.rotation));
  });

  var physicsItem = {
    mesh: tvGroup,
    physics: body };


  physicsItem.physics.velocity.set(0, -20, 0);
  // const angularRandomness = 10;
  // physicsItem.physics.angularVelocity.set(
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)),
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)),
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)))
  // physicsItem.physics.angularDamping = 0.8;

  physicsItems.push(physicsItem);
}

function createTree()
{
  let body = physics.createBody(10, { x: 30, y: -10, z: 30 }, { y: -Math.PI * 0.001, x: Math.PI * 0.001 }, PHYSICS_MATERIAL.lowBounce);
  physics.setAngle(body, -Math.PI * 0.5, 'x');
  let shapes = [
  {
    x: 0,
    y: 0,
    z: -2.2,
    topRadius: 1,
    bottomRadius: 6,
    height: 16,
    segments: 10 },

  {
    x: 0,
    y: 0,
    z: -13,
    topRadius: 0.5,
    bottomRadius: 1,
    height: 7,
    segments: 5 },

  {
    x: 0,
    y: 0,
    z: -15,
    topRadius: 3,
    bottomRadius: 2,
    height: 5,
    segments: 7 }];



  stage.models.tree.position.y = 0;
  stage.models.pot.position.y = 0;

  let treeGroup = new Group();
  treeGroup.add(stage.models.tree);
  treeGroup.add(stage.models.pot);
  stage.scene.add(treeGroup);

  shapes.forEach(cylinder => {
    let shape = physics.createCylinderShape(cylinder.topRadius, cylinder.bottomRadius, cylinder.height, cylinder.segments);

    if (showGuides)
    {
      let b = stage.createCylinder(cylinder.topRadius, cylinder.bottomRadius, cylinder.height, cylinder.segments, 0xff0000);
      b.position.set(cylinder.x, cylinder.y, cylinder.z);
      b.rotation.set(0, 0, 0);
      treeGroup.add(b);
    }

    body.addShape(shape, new CANNON.Vec3(cylinder.x, cylinder.y, cylinder.z), new CANNON.Quaternion(0, 0, cylinder.rotation));
  });

  var physicsItem = {
    mesh: treeGroup,
    physics: body };


  // body.velocity.set(-40, 30, -40)
  // const angularRandomness = 5;
  // body.angularVelocity.set(
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)),
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)),
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)))
  // body.angularDamping = 0.8;

  physicsItems.push(physicsItem);

  return physicsItem;
}

function createSnowman()
{
  // let body = physics.createBody(10, {x: 30, y: -10, z: 30}, {y: -Math.PI * 0.001, x: Math.PI * 0.001}, PHYSICS_MATERIAL.lowBounce);
  let body = physics.createBody(10, { x: 30, y: -10, z: 30 }, { y: 0, x: Math.PI * .5 }, PHYSICS_MATERIAL.normalBounce);
  physics.setAngle(body, -Math.PI * 0.5, 'x');
  let shapes = [
  {
    x: 0,
    y: 2.5,
    z: 0,
    radius: 3 },

  {
    x: 0,
    y: 5,
    z: 0,
    radius: 2.5 },

  {
    x: 0,
    y: 9.5,
    z: 0,
    radius: 1.7 }];



  stage.models.snowman.position.y = 0;

  let snowmanGroup = new Group();
  snowmanGroup.add(stage.models.snowman);
  stage.scene.add(snowmanGroup);

  shapes.forEach(sphere => {
    let shape = physics.createSphereShape(sphere.radius);

    if (showGuides)
    {
      let b = stage.createSphere(sphere.radius, 0xff0000);
      b.position.set(sphere.x, sphere.y, sphere.z);
      b.rotation.set(0, 0, 0);
      snowmanGroup.add(b);
    }

    body.addShape(shape, new CANNON.Vec3(sphere.x, sphere.y, sphere.z), new CANNON.Quaternion(0, 0, 0));
  });

  var physicsItem = {
    mesh: snowmanGroup,
    physics: body };


  // body.velocity.set(-40, 30, -40)
  // const angularRandomness = 5;
  // body.angularVelocity.set(
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)),
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)),
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)))
  // body.angularDamping = 0.8;

  physicsItems.push(physicsItem);

  return physicsItem;
}

function createStar()
{


  // let body = physics.createBody(10, {x: 30, y: -10, z: 30}, {y: -Math.PI * 0.001, x: Math.PI * 0.001}, PHYSICS_MATERIAL.lowBounce);
  let body = physics.createBody(1, { x: 30, y: -10, z: 30 }, { y: 0, x: Math.PI * .5 }, PHYSICS_MATERIAL.normalBounce);
  // physics.setAngle(body, -Math.PI * 0.5, 'x');
  let shapes = [
  {
    x: 0,
    y: 0,
    z: 0,
    topRadius: 1,
    bottomRadius: 1,
    height: 0.5,
    segments: 5 }];



  let star = stars.shift();
  star.position.y = 0;




  shapes.forEach(cylinder => {
    let shape = physics.createCylinderShape(cylinder.topRadius, cylinder.bottomRadius, cylinder.height, cylinder.segments);

    if (showGuides)
    {
      let b = stage.createCylinder(cylinder.topRadius, cylinder.bottomRadius, cylinder.height, cylinder.segments, 0xff0000);
      b.position.set(cylinder.x, cylinder.y, cylinder.z);
      b.rotation.set(0, 0, 0);
      star.add(b);
    }

    body.addShape(shape, new CANNON.Vec3(cylinder.x, cylinder.y, cylinder.z), new CANNON.Quaternion(0, 0, cylinder.rotation));
  });


  var physicsItem = {
    mesh: star,
    physics: body };


  // body.velocity.set(-40, 30, -40)
  // const angularRandomness = 5;
  // body.angularVelocity.set(
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)),
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)),
  // 	((Math.random() * angularRandomness) - (angularRandomness/2)))
  // body.angularDamping = 0.8;

  physicsItems.push(physicsItem);

  return physicsItem;
}

next();